﻿using RestSharp;
using System;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace ClientUploader
{
    class Program
    {
        //接口地址
        //const string upload_url= "http://localhost:12345/File/UploadApi";
        const string upload_url = "http://10.185.1.41:88/File/UploadApi";
        static async Task Main(string[] args)
        {
            string file_path = "";
            if (args.Length == 0)
            {                
                Console.WriteLine("请输入要上传的文件路径");
                file_path = Console.ReadLine();                
            }
            if (!string.IsNullOrEmpty(file_path)&&File.Exists(file_path))
            {
                ProgressBar progressBar = new ProgressBar(Console.CursorLeft, Console.CursorTop, 50, ProgressBarType.Character);
                await SliceUploadAsync(file_path, progressBar.Dispaly);
            }
            else
            {
                Console.WriteLine("指定的文件不存在");
                Console.ReadLine();
            }
        }

        /// <summary>
        /// 切片上传
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="displayProgress"></param>
        /// <returns></returns>
        public static async Task<bool> SliceUploadAsync(string filePath, Func<int, int> displayProgress = null)
        {
            try
            {
                string filename = Path.GetFileName(filePath);
                string md5 = GetMD5HashFromFile(filePath);
                var client = new RestClient(upload_url);
                client.Timeout = -1;
                var request = new RestRequest(Method.POST);
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine($"开始上传文件[{filename}]...{DateTime.Now.ToString("yy/MM/dd HH:mm:ss")}");
                Console.WriteLine();
                using (FileStream fsRead = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                {
                    //文件总长度
                    long left = fsRead.Length;
                    //存储读取结果  
                    byte[] bytes = new byte[1024 * 1024];
                    //每次读取长度  
                    int maxLength = bytes.Length;
                    int total = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(left / 1024 / 1024)));
                    int index = 0;
                    long start = 0;
                    int num = 0;
                    request.AddParameter("md5", md5);
                    request.AddParameter("total", total);
                    request.AddParameter("fileName", filename);

                    while (left > 0)
                    {
                        fsRead.Position = start;
                        num = 0;
                        if (left < maxLength)
                            num = await fsRead.ReadAsync(bytes, 0, Convert.ToInt32(left));
                        else
                            num = await fsRead.ReadAsync(bytes, 0, maxLength);
                        if (num == 0)
                            break;
                        if (request.Files.Count > 0)
                            request.Files.RemoveAt(0);
                        if (request.Parameters.Count(u => u.Name == "index") > 0)
                            request.Parameters.Remove(request.Parameters.Where(u => u.Name == "index").FirstOrDefault());

                        request.AddFile("data", bytes, filename);
                        request.AddParameter("index", index);
                        IRestResponse response = await client.ExecuteAsync(request);
                        if (index == 0)
                        {
                            //Console.WriteLine(response.Content);
                            Response resp = JsonHelper.JsonDeserialize<Response>(response.Content);
                            if (resp.code == 2)
                            {
                                Console.ForegroundColor = ConsoleColor.Cyan;
                                Console.WriteLine($"\n{resp.message}\n");
                                index = Convert.ToInt32(resp.data.index) - 1;
                                if (index < 0)
                                    index = 0;
                                start = index * maxLength;
                                left = left - start;
                                //num = await fsRead.ReadAsync(bytes, 0, maxLength);
                            }
                            else if (resp.code == 3)
                            {
                                Console.WriteLine($"\n {filename}已上传，确定要覆盖吗? y-覆盖，n-跳过, y/n");
                                is_rewrite:
                                string is_rewrite = Console.ReadLine();
                                if (is_rewrite == "y")
                                {
                                    //一切从头来
                                    num = 0;
                                    start = 0;
                                    left = fsRead.Length;
                                    index = -1;
                                    if (request.Files.Count > 0)
                                        request.Files.RemoveAt(0);
                                    if (request.Parameters.Count(u => u.Name == "index") > 0)
                                        request.Parameters.Remove(request.Parameters.Where(u => u.Name == "index").FirstOrDefault());
                                    request.AddParameter("rewrite", is_rewrite);
                                }
                                else if (is_rewrite == "n")
                                {
                                    request.AddParameter("rewrite", is_rewrite);
                                    Console.WriteLine("已跳过");
                                    return true;
                                }
                                else
                                {
                                    Console.ForegroundColor = ConsoleColor.Red;
                                    Console.WriteLine("无效参数，请重新输入");
                                    Console.ForegroundColor = ConsoleColor.Yellow;
                                    goto is_rewrite;
                                    //return false;
                                }
                            }
                        }
                        //增加大于0的条件是，当重写的时候，index会出现-1的情况；
                        if (displayProgress != null && index > 0) displayProgress(Convert.ToInt32(index / (total * 1.0) * 100));
                        start += num;
                        left -= num;
                        index++;
                    }
                }                
                
            }
            catch(Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine($"上传失败:{ex.Message},{ex.StackTrace}");
                return false;
            }
            return true;
        }

        private static string GetMD5HashFromFile(string fileName)
        {
            try
            {
                FileStream file = new FileStream(fileName, FileMode.Open);
                System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                byte[] retVal = md5.ComputeHash(file);
                file.Close();

                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < retVal.Length; i++)
                {
                    sb.Append(retVal[i].ToString("x2"));
                }
                return sb.ToString();
            }
            catch (Exception ex)
            {
                throw new Exception("GetMD5HashFromFile() fail,error:" + ex.Message);
            }
        }
    }
}
